import argon2 from 'argon2';
import User from '../models/user.js';
import redisClient from '../utils/redis.js';
import { decryptData } from '../utils/crypto.js';
import crypto from 'crypto';
import jwt from 'jsonwebtoken';
import path from 'path';
import fs from 'fs';
import { fileURLToPath } from 'url';

// 获取当前文件的路径
const __filename = fileURLToPath(import.meta.url);
// 获取当前文件的目录路径
const __dirname = path.dirname(__filename);


// 安全配置参数
const SECURITY_CONFIG = {
  MAX_PWD_ATTEMPTS: 99, // 同一邮箱最大错误次数
  IP_LIMIT_WINDOW: 60 * 60, // IP限制窗口期（1小时）
  IP_MAX_REQUESTS: 50, // 同一IP最大请求次数
  LOCK_DURATION: 30 * 60, // 账户锁定时间（30分钟）
  RANDOM_DELAY: [500, 1000] // 防探测随机延迟（0.5-1.5秒）
};

// 登录接口（邮箱+密码）
export const loginWithPassword = async (ctx) => {
  const { encryptedData } = ctx.request.body;

  try {
    // === 1. IP频率限制 ===
    // const ipKey = `ip_limit:${clientIP}`;
    // const ipCount = await redisClient.incr(ipKey);
    // if (ipCount === 1) await redisClient.expire(ipKey, SECURITY_CONFIG.IP_LIMIT_WINDOW);
    // if (ipCount > SECURITY_CONFIG.IP_MAX_REQUESTS) {
    //   ctx.status = 429;
    //   ctx.body = { code: 'TOO_MANY_REQUESTS', message: '请求过于频繁' };
    //   return;
    // }

    // === 2. 解密数据 ===
    const { email, password } = await decryptData(encryptedData);
    console.log('%c [ email, password ]-43', 'font-size:13px; background:pink; color:#bf2c9f;', email, password)

    // === 3. 防邮箱探测逻辑 ===
    const user = await User.findOne({ where: { email } });
    if (!user) {
      ctx.status = 404;
      ctx.body = { code: 'USER_NOT_FOUND', message: '用户不存在' };
      return;
    }
    const errorKey = `pwd_attempts:${email}`;
    const attempts = await redisClient.get(errorKey) || 0;

    // 随机延迟响应（防御时序攻击）
    const delay = Math.floor(Math.random() * (SECURITY_CONFIG.RANDOM_DELAY - SECURITY_CONFIG.RANDOM_DELAY)) + SECURITY_CONFIG.RANDOM_DELAY;
    await new Promise(resolve => setTimeout(resolve, delay));

    // === 4. 错误次数验证 ===
    if (attempts >= SECURITY_CONFIG.MAX_PWD_ATTEMPTS) {
      ctx.status = 403;
      ctx.body = { code: 'ACCOUNT_LOCKED', message: '账户已锁定，请30分钟后重试' };
      return;
    }

    // === 5. 统一认证响应===
    const result = await argon2.verify(user.password, password);
    if (!result) {
      ctx.body = { code: 'AUTH_FAILED', message: '认证失败' }; // 统一提示
      await redisClient.incr(errorKey);
      await redisClient.expire(errorKey, SECURITY_CONFIG.LOCK_DURATION);
      return;
    }
    const KEY_PATH = path.resolve(__dirname, "../utils", 'keys');
    const privateKey = fs.readFileSync(path.join(KEY_PATH, 'jwt-private.pem'), 'utf8');
    // 使用 crypto.createPrivateKey 加载和解密私钥
    const decryptedPrivateKey = crypto.createPrivateKey({
      key: privateKey,
      passphrase: process.env.JWT_PASSPHRASE // 加密私钥的密码
    });

    // 将 PrivateKeyObject 转换为 PEM 格式的字符串
    const privateKeyPEM = decryptedPrivateKey.export({
      type: 'pkcs8', // 或 'pkcs1'
      format: 'pem'
    });
    // === 6. 登录成功处理 ===
    let payload = {
      userId: user.id,
      username: user.username,
    };
    // 生成安全令牌（示例）
    function generateSecureToken(payload) {
      return jwt.sign(payload, privateKeyPEM, { algorithm: 'RS256', expiresIn: '72h' });
    }
    const token = generateSecureToken(payload); // 生成安全令牌
    await redisClient.del(errorKey); // 清除错误计数

    ctx.body = {
      code: 'SUCCESS',
      data: { token, userId: user.id }
    };

  } catch (e) {
    console.error('Error in loginWithPassword:', e);
    ctx.status = 500;
    ctx.body = { code: 'SERVER_ERROR', message: '服务异常' };
  }
};

export const logout = async (ctx) => {
  const token = ctx.headers.authorization?.split(' ');

  if (!token) {
    ctx.throw(401, {
      code: 'MISSING_TOKEN',
      message: '未提供身份凭证'
    });
  }

  try {
    const decoded = jwt.verify(token, publicKey, { algorithms: ['RS256'] });
    const remainingTTL = decoded.exp - Math.floor(Date.now() / 1000);

    // 将 Token 加入黑名单
    if (remainingTTL > 0) {
      await redisClient.set(`blacklist:${token}`, 'logout', remainingTTL);
    }

    ctx.body = { code: 'SUCCESS', message: '注销成功' };
  } catch (err) {
    handleAuthError(ctx, err);
  }
};